

#include <stdio.h>
#include <iostream>
#include <chrono>
#include <thread>

#define DEF_MYPT_C_FUNCTION_BODY
#include "ttds/ttds.h"

struct _msg
{
    const char *from_thread;
    int value;
};
typedef struct _msg msg_t;
message_queue_def( g_the_msg, 1024 );

struct my_thread_a
{
    ttds_OBJECT(thread);
    int n;
    const char *name;
};

int my_thread_entry_a( ttds_thread_t *p )
{
    printf("entering my_thread_entry_a p=%p\n", p);
    ttds_DEF_THIS(p, struct my_thread_a, thread );

    ttds_BEGIN(p_this->thread);
    printf("# thread %s started\n", p_this->name);
    while (1)
    {
        msg_t msg;
        int tx_size;
        msg.from_thread = p_this->name;
        msg.value = p_this->n;
        message_queue_send( message_queue_ptr(g_the_msg), &msg, sizeof(msg), tx_size);
        printf("* thread %s txsize=%d\n", p_this->name, tx_size );
        ttds_thread_delay((1+rand()%3) * 1000 );
    }
    ttds_END();
}

void my_thread_a_init(struct my_thread_a *p_this, const char *name)
{
    ttds_thread_init(&p_this->thread, my_thread_entry_a);
    p_this->name = name;
    p_this->n = 0;
}

struct my_thread_b
{
    ttds_OBJECT(thread);
    int n;
    const char *name;
    int i;
};
int my_thread_entry_b( ttds_thread_t *p)
{
    ttds_DEF_THIS(p, struct my_thread_b, thread );

    ttds_BEGIN(p_this->thread);
    printf("# thread %s started\n", p_this->name);
    while (1)
    {
        int rx_size;
        msg_t msg;
        message_queue_recv( message_queue_ptr(g_the_msg), &msg, sizeof(msg), rx_size, -1 );
        printf("### rx_size=%d\n", rx_size );
        if (rx_size == sizeof(msg)){
            printf("* message queue  msg recv from thread %s value=%d\n", msg.from_thread, msg.value );
        }
        p_this->n++;
    }
    ttds_END();
}

void my_thread_b_init(struct my_thread_b *p_this, const char *name)
{
    ttds_thread_init(&p_this->thread, my_thread_entry_b);
    p_this->n = 0;
    p_this->name = name;
}

static void __timer_callback_15seconds( ttds_timer_t *p_this, void *arg)
{
    ttds_loop_t *p_loop = (ttds_loop_t*)arg;

    printf("Stop ALL!\n");
    ttds_loop_destroy(p_loop);
}

static void __select4delay( ttds_loop_t *p_this, int delay, void *arg)
{
    //printf("     ------------ delay %d -------------\n", delay );
    if (delay > 0)
        std::this_thread::sleep_for( std::chrono::milliseconds( delay ) );
}

static void ticker_init();
int main(int argc, char **argv)
{
    ttds_loop_t loop;
    ttds_timer_t timer;
    struct my_thread_a a1, a2;
    struct my_thread_b b1;

    ticker_init();

    message_queue_init_internal_pool( message_queue_ptr(g_the_msg), sizeof(msg_t), g_the_msg );
    my_thread_a_init(&a1, "a1");
    my_thread_a_init(&a2, "a2");
    my_thread_b_init(&b1, "b1");

    ttds_loop_init( &loop );
    ttds_loop_add( &loop, &a1.thread );
    ttds_loop_add( &loop, &a2.thread );
    ttds_loop_add( &loop, &b1.thread );

    ttds_thread_startup( &a1.thread );
    ttds_thread_startup( &a2.thread );
    ttds_thread_startup( &b1.thread );

    ttds_timer_init( &timer, __timer_callback_15seconds, &loop );
    ttds_loop_timer_start( &loop, &timer, 15000 );

    while ( !ttds_loop_empty(&loop)){
        int delay = ttds_loop_poll(&loop);
        if (delay > 0){
            std::this_thread::sleep_for( std::chrono::milliseconds( delay ) );
        }
    }

    ttds_timer_destroy( &timer );
    
    return 0;
}

std::chrono::time_point<std::chrono::steady_clock> g_tp_last;

static void ticker_init()
{
    auto now = std::chrono::steady_clock::now();
    g_tp_last = now;
}

int32_t g_ms_offset = 0;
int32_t ttds_thread_sys_tick_get_ms()
{
    auto now = std::chrono::steady_clock::now();
    auto diff_ms = std::chrono::duration_cast<std::chrono::milliseconds>( now - g_tp_last ).count();
    return diff_ms;
}
